#pragma once

#include <uapi/cdefs.h>

#define CPUID_1_EDX 0
#define CPUID_1_ECX 1
#define CPUID_7_0_EBX 2
#define CPUID_7_0_ECX 3
#define CPUID_7_0_EDX 4
#define CPUID_80000001_EDX 5
#define CPUID_80000001_ECX 6
#define CPUID_8000000A_EDX 7
#define CPUID_LEAF_MAX 16

#define CPUID_BIT(leaf, bit) ((leaf)*32 + (bit))

/* cpuid(1): edx */
#define CPUID_FEATURE_FPU CPUID_BIT(CPUID_1_EDX, 0)
#define CPUID_FEATURE_VME CPUID_BIT(CPUID_1_EDX, 1)
#define CPUID_FEATURE_DE CPUID_BIT(CPUID_1_EDX, 2)
#define CPUID_FEATURE_PSE CPUID_BIT(CPUID_1_EDX, 3)
#define CPUID_FEATURE_TSC CPUID_BIT(CPUID_1_EDX, 4)
#define CPUID_FEATURE_MSR CPUID_BIT(CPUID_1_EDX, 5)
#define CPUID_FEATURE_PAE CPUID_BIT(CPUID_1_EDX, 6)
#define CPUID_FEATURE_MCE CPUID_BIT(CPUID_1_EDX, 7)
#define CPUID_FEATURE_CX8 CPUID_BIT(CPUID_1_EDX, 8)
#define CPUID_FEATURE_APIC CPUID_BIT(CPUID_1_EDX, 9)
/* reserved				CPUID_BIT(CPUID_1_EDX, 10) */
#define CPUID_FEATURE_SEP CPUID_BIT(CPUID_1_EDX, 11)
#define CPUID_FEATURE_MTRR CPUID_BIT(CPUID_1_EDX, 12)
#define CPUID_FEATURE_PGE CPUID_BIT(CPUID_1_EDX, 13)
#define CPUID_FEATURE_MCA CPUID_BIT(CPUID_1_EDX, 14)
#define CPUID_FEATURE_CMOV CPUID_BIT(CPUID_1_EDX, 15)
#define CPUID_FEATURE_PAT CPUID_BIT(CPUID_1_EDX, 16)
#define CPUID_FEATURE_PSE36 CPUID_BIT(CPUID_1_EDX, 17)
#define CPUID_FEATURE_PN CPUID_BIT(CPUID_1_EDX, 18)
#define CPUID_FEATURE_CLFLUSH CPUID_BIT(CPUID_1_EDX, 19)
/* reserved				CPUID_BIT(CPUID_1_EDX, 20) */
#define CPUID_FEATURE_DS CPUID_BIT(CPUID_1_EDX, 21)
#define CPUID_FEATURE_ACPI CPUID_BIT(CPUID_1_EDX, 22)
#define CPUID_FEATURE_MMX CPUID_BIT(CPUID_1_EDX, 23)
#define CPUID_FEATURE_FXSR CPUID_BIT(CPUID_1_EDX, 24)
#define CPUID_FEATURE_SSE CPUID_BIT(CPUID_1_EDX, 25)
#define CPUID_FEATURE_SSE2 CPUID_BIT(CPUID_1_EDX, 26)
#define CPUID_FEATURE_SS CPUID_BIT(CPUID_1_EDX, 27)
#define CPUID_FEATURE_HT CPUID_BIT(CPUID_1_EDX, 28)
#define CPUID_FEATURE_TM CPUID_BIT(CPUID_1_EDX, 29)
#define CPUID_FEATURE_IA64 CPUID_BIT(CPUID_1_EDX, 30)
#define CPUID_FEATURE_PBE CPUID_BIT(CPUID_1_EDX, 31)

/* cpuid(1): ecx */
#define CPUID_FEATURE_SSE3 CPUID_BIT(CPUID_1_ECX, 0)
#define CPUID_FEATURE_PCLMULQDQ CPUID_BIT(CPUID_1_ECX, 1)
#define CPUID_FEATURE_DTES64 CPUID_BIT(CPUID_1_ECX, 2)
#define CPUID_FEATURE_MONITOR CPUID_BIT(CPUID_1_ECX, 3)
#define CPUID_FEATURE_DS_CPL CPUID_BIT(CPUID_1_ECX, 4)
#define CPUID_FEATURE_VMX CPUID_BIT(CPUID_1_ECX, 5)
#define CPUID_FEATURE_SMX CPUID_BIT(CPUID_1_ECX, 6)
#define CPUID_FEATURE_EST CPUID_BIT(CPUID_1_ECX, 7)
#define CPUID_FEATURE_TM2 CPUID_BIT(CPUID_1_ECX, 8)
#define CPUID_FEATURE_SSSE3 CPUID_BIT(CPUID_1_ECX, 9)
#define CPUID_FEATURE_CID CPUID_BIT(CPUID_1_ECX, 10)
#define CPUID_FEATURE_SDBG CPUID_BIT(CPUID_1_ECX, 11)
#define CPUID_FEATURE_FMA CPUID_BIT(CPUID_1_ECX, 12)
#define CPUID_FEATURE_CX16 CPUID_BIT(CPUID_1_ECX, 13)
#define CPUID_FEATURE_XTPR CPUID_BIT(CPUID_1_ECX, 14)
#define CPUID_FEATURE_PDCM CPUID_BIT(CPUID_1_ECX, 15)
/* reserved				CPUID_BIT(CPUID_1_ECX, 16) */
#define CPUID_FEATURE_PCID CPUID_BIT(CPUID_1_ECX, 17)
#define CPUID_FEATURE_DCA CPUID_BIT(CPUID_1_ECX, 18)
#define CPUID_FEATURE_SSE4_1 CPUID_BIT(CPUID_1_ECX, 19)
#define CPUID_FEATURE_SSE4_2 CPUID_BIT(CPUID_1_ECX, 20)
#define CPUID_FEATURE_X2APIC CPUID_BIT(CPUID_1_ECX, 21)
#define CPUID_FEATURE_MOVBE CPUID_BIT(CPUID_1_ECX, 22)
#define CPUID_FEATURE_POPCNT CPUID_BIT(CPUID_1_ECX, 23)
#define CPUID_FEATURE_TSC_DEADLINE_TIMER CPUID_BIT(CPUID_1_ECX, 24)
#define CPUID_FEATURE_AES CPUID_BIT(CPUID_1_ECX, 25)
#define CPUID_FEATURE_XSAVE CPUID_BIT(CPUID_1_ECX, 26)
#define CPUID_FEATURE_OSXSAVE CPUID_BIT(CPUID_1_ECX, 27)
#define CPUID_FEATURE_AVX CPUID_BIT(CPUID_1_ECX, 28)
#define CPUID_FEATURE_F16C CPUID_BIT(CPUID_1_ECX, 29)
#define CPUID_FEATURE_RDRAND CPUID_BIT(CPUID_1_ECX, 30)
#define CPUID_FEATURE_HYPERVISOR CPUID_BIT(CPUID_1_ECX, 31)

/* cpuid(7, 0): ebx */
#define CPUID_FEATURE_FSGSBASE CPUID_BIT(CPUID_7_0_EBX, 0)

/* cpuid(0x80000001): edx */
/* duplicated (fpu)			CPUID_BIT(CPUID_80000001_EDX, 0) */
/* duplicated (vme)			CPUID_BIT(CPUID_80000001_EDX, 1) */
/* duplicated (de)			CPUID_BIT(CPUID_80000001_EDX, 2) */
/* duplicated (pse)			CPUID_BIT(CPUID_80000001_EDX, 3) */
/* duplicated (tsc)			CPUID_BIT(CPUID_80000001_EDX, 4) */
/* duplicated (msr)			CPUID_BIT(CPUID_80000001_EDX, 5) */
/* duplicated (pae)			CPUID_BIT(CPUID_80000001_EDX, 6) */
/* duplicated (mce)			CPUID_BIT(CPUID_80000001_EDX, 7) */
/* duplicated (cx8)			CPUID_BIT(CPUID_80000001_EDX, 8) */
/* duplicated (apic)			CPUID_BIT(CPUID_80000001_EDX, 9) */
/* reserved				CPUID_BIT(CPUID_80000001_EDX, 10) */
#define CPUID_FEATURE_SYSCALL CPUID_BIT(CPUID_80000001_EDX, 11)
/* duplicated (mtrr)			CPUID_BIT(CPUID_80000001_EDX, 12) */
/* duplicated (pge)			CPUID_BIT(CPUID_80000001_EDX, 13) */
/* duplicated (mca)			CPUID_BIT(CPUID_80000001_EDX, 14) */
/* duplicated (cmov)			CPUID_BIT(CPUID_80000001_EDX, 15) */
/* duplicated (pat)			CPUID_BIT(CPUID_80000001_EDX, 16) */
/* duplicated (pse36)			CPUID_BIT(CPUID_80000001_EDX, 17) */
/* reserved				CPUID_BIT(CPUID_80000001_EDX, 18) */
#define CPUID_FEATURE_MP CPUID_BIT(CPUID_80000001_EDX, 19)
#define CPUID_FEATURE_NX CPUID_BIT(CPUID_80000001_EDX, 20)
/* reserved				CPUID_BIT(CPUID_80000001_EDX, 21) */
#define CPUID_FEATURE_MMXEXT CPUID_BIT(CPUID_80000001_EDX, 22)
/* duplicated (mmx)			CPUID_BIT(CPUID_80000001_EDX, 23) */
/* duplicated (fxsr)			CPUID_BIT(CPUID_80000001_EDX, 24) */
#define CPUID_FEATURE_FXSR_OPT CPUID_BIT(CPUID_80000001_EDX, 25)
#define CPUID_FEATURE_PDPE1GB CPUID_BIT(CPUID_80000001_EDX, 26)
#define CPUID_FEATURE_RDTSCP CPUID_BIT(CPUID_80000001_EDX, 27)
/* reserved				CPUID_BIT(CPUID_80000001_EDX, 28) */
#define CPUID_FEATURE_LM CPUID_BIT(CPUID_80000001_EDX, 29)
#define CPUID_FEATURE_3DNOWEXT CPUID_BIT(CPUID_80000001_EDX, 30)
#define CPUID_FEATURE_3DNOW CPUID_BIT(CPUID_80000001_EDX, 31)

/* cpuid(0x80000001): ecx */
#define CPUID_FEATURE_LAHF_LM CPUID_BIT(CPUID_80000001_ECX, 0)
#define CPUID_FEATURE_CMP_LEGACY CPUID_BIT(CPUID_80000001_ECX, 1)
#define CPUID_FEATURE_SVM CPUID_BIT(CPUID_80000001_ECX, 2)
#define CPUID_FEATURE_EXTAPIC CPUID_BIT(CPUID_80000001_ECX, 3)
#define CPUID_FEATURE_CR8LEGACY CPUID_BIT(CPUID_80000001_ECX, 4)
#define CPUID_FEATURE_ABM CPUID_BIT(CPUID_80000001_ECX, 5)
#define CPUID_FEATURE_SSE4A CPUID_BIT(CPUID_80000001_ECX, 6)
#define CPUID_FEATURE_MISALIGNSSE CPUID_BIT(CPUID_80000001_ECX, 7)
#define CPUID_FEATURE_3DNOWPREFETCH CPUID_BIT(CPUID_80000001_ECX, 8)
#define CPUID_FEATURE_OSVW CPUID_BIT(CPUID_80000001_ECX, 9)
#define CPUID_FEATURE_IBS CPUID_BIT(CPUID_80000001_ECX, 10)
#define CPUID_FEATURE_XOP CPUID_BIT(CPUID_80000001_ECX, 11)
#define CPUID_FEATURE_SKINIT CPUID_BIT(CPUID_80000001_ECX, 12)
#define CPUID_FEATURE_WDT CPUID_BIT(CPUID_80000001_ECX, 13)
/* reserved				CPUID_BIT(CPUID_80000001_ECX, 14) */
#define CPUID_FEATURE_LWP CPUID_BIT(CPUID_80000001_ECX, 15)
#define CPUID_FEATURE_FMA4 CPUID_BIT(CPUID_80000001_ECX, 16)
#define CPUID_FEATURE_TCE CPUID_BIT(CPUID_80000001_ECX, 17)
/* reserved				CPUID_BIT(CPUID_80000001_ECX, 18) */
#define CPUID_FEATURE_NODEID_MSR CPUID_BIT(CPUID_80000001_ECX, 19)
/* reserved				CPUID_BIT(CPUID_80000001_ECX, 20) */
#define CPUID_FEATURE_TBM CPUID_BIT(CPUID_80000001_ECX, 21)
#define CPUID_FEATURE_TOPOEXT CPUID_BIT(CPUID_80000001_ECX, 22)
#define CPUID_FEATURE_PERFCTR_CORE CPUID_BIT(CPUID_80000001_ECX, 23)
#define CPUID_FEATURE_PERFCTR_NB CPUID_BIT(CPUID_80000001_ECX, 24)

/* cpuid(0x8000000a): edx */
#define CPUID_FEATURE_NPT CPUID_BIT(CPUID_8000000A_EDX, 0)
#define CPUID_FEATURE_LBRV CPUID_BIT(CPUID_8000000A_EDX, 1)
#define CPUID_FEATURE_SVML CPUID_BIT(CPUID_8000000A_EDX, 2)
#define CPUID_FEATURE_NRIPS CPUID_BIT(CPUID_8000000A_EDX, 3)
#define CPUID_FEATURE_TSCREATEMSR CPUID_BIT(CPUID_8000000A_EDX, 4)
#define CPUID_FEATURE_VMCBCLEAN CPUID_BIT(CPUID_8000000A_EDX, 5)
#define CPUID_FEATURE_FLUSHBYASID CPUID_BIT(CPUID_8000000A_EDX, 6)
#define CPUID_FEATURE_DECODEASSISTS CPUID_BIT(CPUID_8000000A_EDX, 7)
/* reserved				CPUID_BIT(CPUID_8000000A_EDX, 8) */
/* reserved				CPUID_BIT(CPUID_8000000A_EDX, 9) */
#define CPUID_FEATURE_PAUSEFILTER CPUID_BIT(CPUID_8000000A_EDX, 10)
/* reserved				CPUID_BIT(CPUID_8000000A_EDX, 11) */
#define CPUID_FEATURE_PFTHRESHOLD CPUID_BIT(CPUID_8000000A_EDX, 12)
#define CPUID_FEATURE_AVIC CPUID_BIT(CPUID_8000000A_EDX, 13)
/* reserved				31:14 */

void cpuid_init(void);
bool cpuid_has(int bit);
